/*
 *  Copyright (C) 2010 Martin Haulrich <mwh.isv@cbs.dk> and Matthias Buch-Kromann <mbk.isv@cbs.dk>
 *
 *  This file is part of the IncrementalParser package.
 *
 *  The IncrementalParser program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.osdtsystem.incparser.featureextraction;

import org.osdtsystem.incparser.features.FeatureAggregator;
import org.osdtsystem.incparser.features.FeatureHandler;
import org.osdtsystem.incparser.graphs.Graph;
import org.osdtsystem.incparser.graphs.LocalGraph;
import org.osdtsystem.incparser.graphs.ConllAdapter;

/**
 *
 * @author Martin Haulrich and Matthias Buch-Kromann
 */
public class MstFeatureExtractorLabelledNew extends ConllFeatureExtractor implements MstFeatureExtractorLabelled {
    // Feature groups
    final static int GROUP_MST_LABELLED = reserveFeatureGroups(1, "GROUP_MST_LABELLED");
    final static int GROUP_MST_LABELLED_DEP = reserveFeatureGroups(14, "GROUP_MST_LABELLED_DEP");
    final static int GROUP_MST_LABELLED_HEAD = reserveFeatureGroups(14, "GROUP_MST_LABELLED_HEAD");

    public MstFeatureExtractorLabelledNew(ConllAdapter adapter, FeatureHandler featureHandler) {
        super(adapter, featureHandler);
    }

    @Override
    public void extract(FeatureAggregator aggregator, Graph graph, int node) {
        LocalGraph depGraph = graph.localGraph(node, layer);
        int headEdge = 0;
        if (depGraph.inDegree() > 0)
            headEdge = depGraph.inEdge(0);
        int head = depGraph.node(headEdge);
        int type = depGraph.type(headEdge);
        extractDependentFeatures(aggregator, graph, node, type, head < node);
        extractHeadFeatures(aggregator, graph, node, type, head < node);
    }

    public final void extractDependentFeatures(FeatureAggregator aggregator, Graph graph, int node, int type,
            boolean headBeforeDep) {
        extractNode(aggregator, graph, GROUP_MST_LABELLED_DEP, node, type, true, headBeforeDep);
    }

    public final void extractHeadFeatures(FeatureAggregator aggregator, Graph graph, int node, int type,
            boolean headBeforeDep) {
        extractNode(aggregator, graph, GROUP_MST_LABELLED_HEAD, node, type, false, headBeforeDep);
    }

    void extractNode(FeatureAggregator aggregator, Graph graph,
            int featureGroup, int node, int type, boolean isChild, boolean headBeforeDep) {
        int nodeLocation = (isChild ? 2 : 0) | (headBeforeDep ? 1 : 0);
        int nodeForm = adapter.form(graph, node);
        int nodePostag = adapter.postag(graph, node);
        int nodePrevPostag = node > 0 ? adapter.postag(graph, node - 1) : FeatureHandler.START;
        int nodeNextPostag = node < graph.nodes() - 1 ? adapter.postag(graph, node + 1) : FeatureHandler.STOP;
        int typeLoc = type * 4 + nodeLocation;

        // Add labeled features
        aggregator.addFeature(combine(featureGroup +  0, type   ));
        aggregator.addFeature(combine(featureGroup +  1, typeLoc));
        aggregator.addFeature(combine(featureGroup +  2, type   , nodeForm, nodePostag));
        aggregator.addFeature(combine(featureGroup +  3, typeLoc, nodeForm, nodePostag));
        aggregator.addFeature(combine(featureGroup +  4, type   , nodePostag));
        aggregator.addFeature(combine(featureGroup +  5, typeLoc, nodePostag));
        aggregator.addFeature(combine(featureGroup +  6, type   , nodePrevPostag, nodePostag));
        aggregator.addFeature(combine(featureGroup +  7, typeLoc, nodePrevPostag, nodePostag));
        aggregator.addFeature(combine(featureGroup +  8, type   , nodePostag, nodeNextPostag));
        aggregator.addFeature(combine(featureGroup +  9, typeLoc, nodePostag, nodeNextPostag));
        aggregator.addFeature(combine(featureGroup + 10, type   , nodePrevPostag, nodePostag, nodeNextPostag));
        aggregator.addFeature(combine(featureGroup + 11, typeLoc, nodePrevPostag, nodePostag, nodeNextPostag));
        aggregator.addFeature(combine(featureGroup + 12, type   , nodeForm));
        aggregator.addFeature(combine(featureGroup + 13, typeLoc, nodeForm));
    }

    @Override
    public void edgeAdded(Graph graph, int layer, int innode, int outnode, int type) {
        if (layer == this.layer)
            outdate(graph, innode);
    }

    @Override
    public void edgeMoved(Graph graph, int layer, int innode, int oldoutnode, int oldtype, int newoutnode, int newtype) {
        if (layer == this.layer)
            outdate(graph, innode);
    }

    @Override
    public void edgeRemoved(Graph graph, int layer, int innode, int outnode, int type) {
        if (layer == this.layer)
            outdate(graph, innode);
    }

    @Override
    public void graphCleared(Graph graph) {
    }

    @Override
    public void intFeatureChanged(Graph graph, int node, int feature, int value, int oldvalue) {
        if (feature == adapter.FORM || feature == adapter.POSTAG) {
            outdate(graph, node);
        }
    }

    @Override
    public void nodeAdded(Graph graph, int node) {
        outdate(graph, node);
    }

    @Override
    public void objectFeatureChanged(Graph graph, int node, int feature, Object value, Object oldvalue) {
    }

    public void edgeTypeChanged(Graph graph, int layer, int innode, int outnode, int oldtype, int newtype) {
        if (layer == this.layer)
            outdate(graph, innode);
    }
}
